/**
 * @file thread.cpp
 * @ingroup Thread
 *
 * @brief Thread super-class implementation
 */

/* --
 * Copyright (c) 2012, Christophe Huriaux
 * Distributed under the terms of the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 * --
 */

#include <thread/thread.h>
#include <sys/prctl.h>

/**
 * @brief Constructor
 *
 *    Initializes the thread object state machine with the given name.
 *
 * @param name Thread name
 */
Thread::Thread(const char* name)
	: name(name), alive(false), stopped(true)
{

}


/**
 * @brief Starts the thread
 *
 *    Causes the thread to begin his execution. The thread is instanciated
 * and the @c Thread::run() entry point is called within the separate thread.
 *
 * @retval 0 If the thread is successfully started
 * @retval -1 If it could not been created
 */
int
Thread::start()
{
	if (isAlive())
		return -1;

	int rc;

	rc = pthread_create(&id, NULL, Thread::__threadEntryPoint, (void*)this);
	if (rc != 0)
		return -1;

	alive = true;
	return 0;
}


/**
 * @brief Gentily asks the thread to stop
 *
 *    Raise a flag to allow the thread to terminates properly and free all
 * allocated resources. The thread may or may not terminate within a decent
 * amount of time, depending on the given @c Thread::run() implementation.
 *
 * @retval 0 The function should never fail and always returns 0
 */
int
Thread::stop()
{
	stopped = true;

	return 0;
}


/**
 * @brief Wait for the thread to terminate
 *
 *    Asks the thread to terminate with a @c Thread::stop() call and wait until
 * it dies.
 *
 * @retval 0 If the thread is effectively dead
 * @retval -1 If something went wrong
 */
int
Thread::join()
{
	void* status;

	stop();
	return pthread_join(id, &status);
}


/**
 * @brief Kill the thread
 *
 *    Don't wait for the thread to cleanup properly his resources and
 * terminates it immediatly.
 *
 * @retval 0 If the thread is effectively dead
 * @retval -1 If something went wrong
 *
 * @note The call thread will nevertheless call his @c Thread::atCleanup() method
 * to let the thread clean some resources if needed.
 */
int
Thread::cancel()
{
	return pthread_cancel(id);
}


/**
 * @brief Cleanup callback
 *
 *     Called when the thread terminates either properly or in a dirty manner.
 * Give a change to the thread to cleanup possibly allocated resources.
 */
void
Thread::atCleanup()
{
	alive = false;
}


/**
 * @brief Thread entry point
 *
 *    This is the static entry point of the thread, called upon thread
 * @c start(). Sets up the thread sub-process name and call the
 * @c Thread::run() member function.
 *
 * @param ptr Pointer to the calling object
 */
void*
Thread::__threadEntryPoint(void* ptr)
{
	void* rc;
	Thread* th = (Thread*)ptr;
	th->alive = true;
	th->stopped = false;

	pthread_cleanup_push(Thread::__threadCleanup, ptr);
	prctl(PR_SET_NAME, (unsigned long)th->getName());
	rc= th->run();
	pthread_cleanup_pop(1);

	return rc;
}


/**
 * @brief Thread exit point
 *
 *    This is the static exit point of the thread, called whenever the
 * thread terminates by itself or through a @c Thread::cancel call. Calls
 * the thread @c Thread::atCleanup() routine.
 *
 * @param ptr Pointer to the calling object
 */
void
Thread::__threadCleanup(void* ptr)
{
	Thread* th = (Thread*)ptr;
	th->atCleanup();
}
